package com.example.annotation.redis;

import com.example.util.redis.IPUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;


/**
 * @author LiYuhang
 * @version 0.1
 * @application
 */
@Aspect
@Component
@Slf4j
public class SubmitLockAspect {
    @Resource
    private RedisTemplate stringRedisTemplate;

    public static final String SPILT_DELIMITER=":";

    @Pointcut("@within(com.example.annotation.redis.SubmitLock) || @annotation(com.example.annotation.redis.SubmitLock)")
    @Order(1)
    public void submitLock(){}

    @Around("submitLock()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {
        StringBuffer stringBuffer = new StringBuffer();
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
           // StringBuffer reqUrl = request.getRequestURL();
           // String uri = request.getRequestURI();
           // String methodType = request.getMethod();
            String ip = IPUtils.getIpAddr(request);
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            String accesstoken = request.getHeader("access-token");
            if(StringUtils.isBlank(accesstoken)){
                accesstoken="";
            }
            //客户端类型
//            String userAgent = request.getHeader("User-Agent");
//            if(StringUtils.isBlank(userAgent)){
//                userAgent="";
//            }
            String className = method.getDeclaringClass().getName();
            String methodName = method.getName();
            /**
             * key = className:methodName:ip:accesstoke:Arrays.toString(reqParams)
             */
            stringBuffer.append(className)
                    .append(SPILT_DELIMITER).append(methodName)
                    .append(SPILT_DELIMITER).append(ip)
                    .append(SPILT_DELIMITER).append(accesstoken);
                    //.append(SPILT_DELIMITER).append(uri)
                  //  .append(SPILT_DELIMITER).append(reqUrl)
                    //   .append(SPILT_DELIMITER).append(methodType)
                    // .append(SPILT_DELIMITER).append(userAgent);

            // 请求参数
            if (point.getArgs() != null) {
                log.info("请求参数：{}",Arrays.toString(point.getArgs()));
               String[] reqParams=new String[point.getArgs().length];
                for (int i = 0; i < point.getArgs().length; i++) {
                    Object obj=point.getArgs()[i];
                    if(obj instanceof MultipartFile){
                        String fileName=((MultipartFile) obj).getOriginalFilename();
                        String fileSize=String.valueOf(((MultipartFile) obj).getSize());
                        reqParams[i]=fileName+"_size_"+fileSize;
                    }else{
                        reqParams[i]=obj.toString();
                    }
                }
                stringBuffer.append(SPILT_DELIMITER).append(Arrays.toString(reqParams));
            }
            //判断是否有值
            if (!stringRedisTemplate.hasKey(stringBuffer.toString())) {
                Object o = point.proceed();
                //redis存数据并 设置失效时间 默认60S
                SubmitLock submitLock = method.getAnnotation(SubmitLock.class);
                long timeOut=submitLock.expireTime() >0 ? submitLock.expireTime() : 60;
                stringRedisTemplate.opsForValue().set(stringBuffer.toString(), "T", timeOut, TimeUnit.SECONDS);
                return o;
            } else {
                log.info("请勿重复提交数据");
                return "{\"code\":\"403\",\"message\":\"请勿重复提交！\"}";
            }
        }catch (Exception e){
            e.printStackTrace();
            log.error("验证重复提交时出现异常！{}",e);
            return "{\"code\":\"500\",\"message\":\"验证重复提交时出现未知异常！\"}";
        }
    }
}
